home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / lib / awf / pass3 < prev   
Text File  |  1995-05-16  |  14KB  |  333 lines

  1. # third pass:  setting lines and pages
  2. # The input language of this pass is basically <width, word> pairs, where
  3. # "word" may have imbedded strangeness (backspaces, etc.) for font changes
  4. # and special characters.  Zero width is not special.  A third field may
  5. # appear to indicate that this is a fragment of a word that can be
  6. # hyphenated; the third field is the width of the hyphen that would have
  7. # to be added if the line broke after this fragment.
  8. # Negative widths denote special operations.  -3 is an error message, the
  9. # second field being the message.  -1 and -2 are control messages to this
  10. # pass, the difference being whether a break is implied or not.  The second
  11. # field is a message type string; more fields may appear as arguments.  The
  12. # semantics of control messages are often -- but not always! -- similar to
  13. # those of troff commands.  For example, "linelen" is .ll, but "center" is
  14. # not semantically equivalent to .ce -- it is related but more primitive.
  15. BEGIN {
  16.        # input and output details
  17.        FS = "\t"
  18.        nobreak = -1
  19.        dobreak = -2
  20.        message = -3
  21.        errs = "awf.errs"       # default only, normally changed by "errsto"
  22.  
  23.        # page setup -- some are defaults only, normally altered by pass 2
  24.        nextlineno = 1
  25.        thispageno = 1
  26.        topmargin = 5
  27.        botmargin = 5
  28.        ind = 0                 # current indent
  29.        tmpind = 0
  30.        pageoffset = ""         # string to emit at start of each line
  31.        nospacemode = 1
  32.        hdrs["CH"] = "- % -"
  33.        nop = split("LH,CH,RH,LF,CF,RF", hdrnames, ",")
  34.        fph = 0                 # print header on first page?
  35.        fill = 1
  36.        adj = "both"
  37.        pagelen = 66
  38.        linelen = 78
  39.  
  40.        # line-builder setup
  41.        line = ""               # line so far, without padding
  42.        paddable = ""           # x means corresp. char in "line" is paddable
  43.        thislinelen = -1        # -1 means nothing there
  44.        cont = " "              # thing to append to continue line
  45.        contlen = 1
  46.        eol = ""                # thing to append to break line
  47.        eollen = 0
  48.        padfrom = "R"           # "L" or "R", alternating for river avoidance
  49.  
  50.        # many spaces, so we can use substr to get any number we need
  51.        sps = "                                                     "
  52.        sps = sps sps sps sps sps sps sps sps sps sps
  53. }
  54. {
  55.        # process word, if any, causing a break if appropriate
  56.        if ($1 >= 0 && thislinelen < 0) {       # word, and first on line
  57.                line = $2
  58.                paddable = substr(sps, 1, length($2))
  59.                thislinelen = $1
  60.        } else if ($1 >= 0 && thislinelen+contlen+$1+$3 <= linelen-ind-tmpind) {
  61.                # word, and it fits on line
  62.                line = line cont $2
  63.                if (cont == " ")
  64.                        paddable = paddable "x"
  65.                else
  66.                        paddable = paddable substr(sps, 1, length(cont))
  67.                paddable = paddable substr(sps, 1, length($2))
  68.                thislinelen += contlen + $1
  69.        } else if ($1 == nobreak || $1 == message)
  70.                nop = 0         # no attention (i.e. break) needed here
  71.        else if ($1 == dobreak && $2 == "need" && \
  72.                                nextlineno + $3 < pagelen + 1 - botmargin)
  73.                nop = 0         # enough space is available, no action needed
  74.        else if ($1 == dobreak && $2 == "toindent" && \
  75.                                        ind + tmpind + thislinelen < ind) {
  76.                # move to indent position within line; there is room
  77.                n = ind - (ind + tmpind + thislinelen)
  78.                line = line substr(sps, 1, n)
  79.                # nothing before this is paddable
  80.                paddable = substr(sps, 1, length(line))
  81.                thislinelen += n
  82.                # prevent padding immediately after this point
  83.                cont = ""
  84.                contlen = 0
  85.        } else if (thislinelen >= 0 || ($1 == dobreak && $2 == "need")) {
  86.                # must emit output, either due to break or "need"
  87.  
  88.                # if at top of page, header
  89.                if (nextlineno == 1) {
  90.                        for (i = int((topmargin-1)/2); i > 0; i--) {
  91.                                print ""
  92.                                nextlineno++
  93.                        }
  94.                        for (hno in hdrnames) {
  95.                                h = hdrnames[hno]
  96.                                if (hdrs[h] ~ /%/) {
  97.                                        n = split(hdrs[h], t, "%")
  98.                                        thispagehdrs[h] = t[1] thispageno t[2]
  99.                                } else
  100.                                        thispagehdrs[h] = hdrs[h]
  101.                        }
  102.                        if (fph || thispageno > 1) {
  103.                                lh = thispagehdrs["LH"]
  104.                                ch = thispagehdrs["CH"]
  105.                                rh = thispagehdrs["RH"]
  106.                                lsp = int((linelen - length(lh ch rh)) / 2)
  107.                                rsp = linelen - length(lh ch rh) - lsp
  108.                                print pageoffset lh substr(sps, 1, lsp) ch substr(sps, 1, rsp) rh
  109.                        } else
  110.                                print ""
  111.                        nextlineno++
  112.                        while (nextlineno <= topmargin) {
  113.                                print ""
  114.                                nextlineno++
  115.                        }
  116.                }
  117.  
  118.                # the current line
  119.                # first, add a trailing hyphen if any
  120.                line = line eol
  121.                paddable = paddable substr(sps, 1, length(eol))
  122.                thislinelen += eollen
  123.  
  124.                # trim trailing spaces if any
  125.                while (line ~ / $/) {
  126.                        line = substr(line, 1, length(line)-1)
  127.                        paddable = substr(paddable, 1, length(line))
  128.                        thislinelen--
  129.                }
  130.  
  131.                # print it in a suitable way
  132.                if (line == "")         # empty always prints as nothing
  133.                        print ""
  134.                else if ($1 < 0 && $2 == "center") {
  135.                        # center it
  136.                        hsp = int((linelen - thislinelen) / 2)
  137.                        if (hsp < 0)
  138.                                hsp = 0
  139.                        print pageoffset substr(sps, 1, ind+tmpind+hsp) line
  140.                } else if (adj == "left" || (adj == "both" && \
  141.                                        ($1 < 0 || index(paddable, "x") == 0)))
  142.                        # no right-margin adjustment (disabled, inappropriate
  143.                        # (line ended by break), or impossible)
  144.                        print pageoffset substr(sps, 1, ind+tmpind) line
  145.                else if (adj == "both") {
  146.                        # hard case -- adjust right margin
  147.                        # sanity check
  148.                        if (length(paddable) != length(line))   # aieeeee
  149.                                printf "awf: %f != %f!\n", length(paddable), \
  150.                                                        length(line) >errs
  151.  
  152.                        # compute parameters
  153.                        textlen = linelen - (ind+tmpind)
  154.                        mustadd = textlen - thislinelen
  155.                        npad = 0        # number of paddable spaces
  156.                        for (tmp = paddable; (i = index(tmp, "x")) > 0; \
  157.                                                        tmp = substr(tmp, i+1))
  158.                                npad++
  159.                        addatall = int(mustadd/npad)    # all grow this much
  160.                        spall = substr(sps, 1, addatall)
  161.                        nmore = mustadd - addatall*npad # this many grow more
  162.  
  163.                        # build padded output text
  164.                        out = substr(sps, 1, ind+tmpind)
  165.                        padno = 0
  166.                        while ((i = index(paddable, "x")) > 0) {
  167.                                out = out substr(line, 1, i)
  168.                                padno++
  169.                                out = out spall
  170.                                if (padfrom == "L") {
  171.                                        if (padno <= nmore)
  172.                                                out = out " "
  173.                                } else {
  174.                                        if (padno > npad-nmore)
  175.                                                out = out " "
  176.                                }
  177.                                line = substr(line, i+1)
  178.                                paddable = substr(paddable, i+1)
  179.                        }
  180.  
  181.                        # print it, plus remnant not processed by loop
  182.                        print pageoffset out line
  183.  
  184.                        # tidy up
  185.                        if (padfrom == "L")
  186.                                padfrom = "R"
  187.                        else
  188.                                padfrom = "L"
  189.                }
  190.  
  191.                # tidy up after output line
  192.                nextlineno++
  193.                line = ""
  194.                paddable = ""
  195.                thislinelen = -1
  196.                tmpind = 0
  197.                nospacemode = 0
  198.  
  199.                # if we broke from a "need", go to bottom of page
  200.                if ($1 == dobreak && $2 == "need")
  201.                        while (nextlineno < pagelen + 1 - botmargin) {
  202.                                print ""
  203.                                nextlineno++
  204.                        }
  205.  
  206.                # footer, if at bottom of page
  207.                if (nextlineno >= pagelen + 1 - botmargin) {
  208.                        for (i = int((botmargin-1)/2); i > 0; i--) {
  209.                                print ""
  210.                                nextlineno++
  211.                        }
  212.                        # header code prepared thispagehdrs
  213.                        lf = thispagehdrs["LF"]
  214.                        cf = thispagehdrs["CF"]
  215.                        rf = thispagehdrs["RF"]
  216.                        lsp = int((linelen - length(lf cf rf)) / 2)
  217.                        rsp = linelen - length(lf cf rf) - lsp
  218.                        print pageoffset lf substr(sps, 1, lsp) cf substr(sps, 1, rsp) rf
  219.                        nextlineno++
  220.                        while (nextlineno <= pagelen) {
  221.                                print ""
  222.                                nextlineno++
  223.                        }
  224.                        nextlineno = 1
  225.                        thispageno++
  226.  
  227.                        # after page break, should not space unnecessarily,
  228.                        # and should pad first line from right
  229.                        nospacemode = 1
  230.                        padfrom = "R"
  231.                }
  232.  
  233.                # we are finally done with emitting output
  234.                # pick up input word, if any
  235.                if ($1 >= 0) {
  236.                        line = $2
  237.                        paddable = substr(sps, 1, length($2))
  238.                        thislinelen = $1
  239.                }
  240.        }
  241.  
  242.        # if we broke, next line should pad from right
  243.        if ($1 == dobreak)
  244.                padfrom = "R"
  245.  
  246.        # cleanup and post-break command processing
  247.        if ($1 >= 0 || $2 == "nohyphen") {
  248.                # reset hyphenation trickery after each word (fragment)
  249.                cont = " "
  250.                contlen = 1
  251.                eol = ""
  252.                eollen = 0
  253.        } else if ($2 == "need" || $2 == "toindent")
  254.                nop = 0         # dealt with above
  255.        else if ($2 == "flush" || $2 == "center")
  256.                nop = 0         # exist only to cause break
  257.        else if ($1 == message)
  258.                print "awf: " $2 >errs
  259.        else if ($2 == "gap") {
  260.                # gap between last word and next one should be >= $3
  261.                if (thislinelen >= 0) {
  262.                        line = line substr(sps, 1, $3-1)
  263.                        paddable = paddable substr(sps, 1, $3-1)
  264.                        thislinelen += $3-1
  265.                }
  266.        } else if ($2 == "tabto") {
  267.                # move to tab stop at $3
  268.                if (thislinelen < 0)
  269.                        thislinelen = 0         # make line exist
  270.                n = $3 - thislinelen
  271.                if (n > 0) {                    # must emit some space
  272.                        line = line substr(sps, 1, n)
  273.                        # nothing before a tab is paddable
  274.                        paddable = substr(sps, 1, length(line))
  275.                        thislinelen += n
  276.                        # suppress space following
  277.                        cont = ""
  278.                        contlen = 0
  279.                }
  280.        } else if ($2 == "errsto")
  281.                errs = $3
  282.        else if ($2 ~ /^[LCR][HF]$/)
  283.                hdrs[$2] = $3
  284.        else if ($2 == "fph")
  285.                fph = $3
  286.        else if ($2 == "space") {
  287.                if (!nospacemode) {
  288.                        # generate an empty line, which will be flushed by
  289.                        # the next word; NB we know "space" caused a flush
  290.                        line = ""
  291.                        paddable = ""
  292.                        thislinelen = linelen + 1
  293.                        nospacemode = 0
  294.                }
  295.        } else if ($2 == "left")
  296.                adj = "left"
  297.        else if ($2 == "both")
  298.                adj = "both"
  299.        else if ($2 == "indent")
  300.                ind = $3
  301.        else if ($2 == "tempindent")
  302.                tmpind = $3
  303.        else if ($2 == "linelen")
  304.                linelen = $3
  305.        else if ($2 == "pagelen")
  306.                pagelen = $3
  307.        else if ($2 == "nospace")
  308.                nospacemode = 1
  309.        else if ($2 == "yesspace")
  310.                nospacemode = 0
  311.        else if ($2 == "hyphen") {
  312.                # discretionary hyphen at this point
  313.                cont = ""
  314.                contlen = 0
  315.                eol = $3
  316.                eollen = $4
  317.        } else if ($2 == "userhyphen") {
  318.                # user-supplied hyphen at this point
  319.                cont = $3
  320.                contlen = $4
  321.                eol = $3
  322.                eollen = $4
  323.        } else if ($2 == "pageoffset")
  324.                pageoffset = substr(sps, 1, $3)
  325.        else
  326.                print "awf: URK -- INTERNAL OPCODE `" $2 "' UNKNOWN" >errs
  327. }
  328. END {
  329.        # second pass is supposed to fake a .ne to flush the last page
  330.        if (nextlineno != 1)
  331.                print "awf: last page not flushed!" >errs
  332. }
  333.